﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using App.Core.Domain.BaseObject;
using App.Core.Dtos;
using App.Core.DataAccess;
using System.Data.Entity;
using App.Core.Domain;
using Omu.ValueInjecter;
using App.Core.Common;
using EntityFramework.Extensions;
using App.Core.Dtos.Goods;

namespace App.Services.Impls
{
    public partial class GoodsPackageServiceImpl : AppServiceBase, IGoodsPackageService
    {
        private readonly CurrentSession _curUser;
        public GoodsPackageServiceImpl()
        {
            _curUser = new CurrentSession();
        }

        public async Task<GoodsPackageDto> GetGoodsPackageAsync(Guid id)
        {
            using (var db = new Db())
            {
                var package = await db.GoodsPackage.Include("Goods").SingleOrDefaultAsync(s=>s.Id == id);
                var packageDto = new GoodsPackageDto();
                packageDto.InjectFrom(package);
                packageDto.Id = package.Id;
                packageDto.Goods = package.Goods.Select(r => new GoodsDto().InjectFrom(r)).Cast<GoodsDto>().ToList();

                return packageDto;
            }
        }

        public GoodsPackageDto GetGoodsPackage(Guid id)
        {
            using (var db = new Db())
            {
                var package = db.GoodsPackage.Include("Goods").SingleOrDefault(s => s.Id == id);
                var packageDto = new GoodsPackageDto();
                packageDto.InjectFrom(package);
                packageDto.Id = package.Id;
                packageDto.Goods = package.Goods.Select(r => new GoodsDto().InjectFrom(r)).Cast<GoodsDto>().ToList();

                return packageDto;
            }
        }

        public async Task<OperationResult> SaveGoodsPackages(BulkDto<GoodsPackageDto> dto)
        {
            using (var db = new Db())
            {
                var curUser = new CurrentSession();
                var exists = new List<string>();
                //批量插入
                foreach (var row in dto.InsertedRows)
                {
					                    if (await db.GoodsPackage.CountAsync(b => b.PackageName == row.PackageName) > 0)
                    {
                        exists.Add(string.Format("名为【{0}】的商品套餐已经存在！", row.PackageName));
                    }
                    else
                    {
					                        var entity = new GoodsPackage();
                        entity.InjectFrom<NotNullInjection>(row);
                        entity.CustomRedeemCode = entity.CustomRedeemCode.ToUpper();
                        db.GoodsPackage.Add(entity);
                    }
                }
                //批量更新
                foreach (var row in dto.UpdatedRows)
                {
                    var entity = await db.GoodsPackage.FindAsync(row.Id);
                    entity.InjectFrom(new NotNullInjection(), row);
                    entity.CustomRedeemCode = entity.CustomRedeemCode.ToUpper();
                }

                //删除
                var deleteArray = dto.DeletedRows.Where(row => row.Id != null).Select(s => s.Id).ToArray();
                if (deleteArray.Length > 0)
                {
                    var goodsPackages = db.GoodsPackage.Include("Goods").Include("RedeemCodes").Where(s => deleteArray.Contains(s.Id)).ToList();
                    db.GoodsPackage.RemoveRange(goodsPackages);
                }

                await db.SaveChangesAsync();

                return new OperationResult() { success = true, message = dto.DeletedRows.Count > 0 ? "数据已经成功删除！" : exists.Count > 0 ? String.Join("<br />", exists) : "保存成功！" };
            }
        }

        public async Task<OperationResult> LinkPackageGoods(Guid packageId, List<Guid> linkGoods)
        {
            using (var db = new Db())
            {
                var package = await db.GoodsPackage.Include("Goods").SingleOrDefaultAsync(s=>s.Id == packageId);
                if (package != null)
                {
                    foreach (var item in linkGoods)
                    {
                        var goods = await db.Goods.FindAsync(item);
                        if (!package.Goods.Contains(goods))
                            package.Goods.Add(goods);
                    }
                    await db.SaveChangesAsync();
                }

                return new OperationResult() { success = true };
            }
        }

        public async Task<OperationResult> CreateRedeemCodes(Guid packageId, int createNumber)
        {
            using (var db = new Db())
            {
                var package = await db.GoodsPackage.SingleAsync(s=>s.Id == packageId);
                if (package.TotalRedeemCode > 0) {
                    return new OperationResult() { success = false, message=string.Format("该套餐已经生成{0}张兑换码，如要重新生成请先清空！" ,package.TotalRedeemCode)};
                }

                var bulks = new List<RedeemCode>();
                var codeNumbers = GetRandomNumbers(createNumber).Distinct().ToList();
                if (codeNumbers.Count() < createNumber) {
                    codeNumbers.AddRange(GetRandomNumbers((createNumber - codeNumbers.Count())+1000));
                }
                var resultCodes = codeNumbers.Distinct().ToArray();
                for (int i= 0; i < createNumber;i++)
                {
                    var code = resultCodes[i];
                    var entity = new RedeemCode();
                    entity.Id = Guid.NewGuid();
                    entity.CodeNumber = package.CustomRedeemCode + code;
                    entity.Package = package;
                    entity.CreationTime = DateTime.Now;
                    entity.CreatorUserId = AppSession.UserId;
                    bulks.Add(entity);
                }

                await db.BulkInsertAsync(bulks);

                package.TotalRedeemCode = createNumber;
                await db.SaveChangesAsync();

                return new OperationResult() { success = true };
            }
        }

        private List<string> GetRandomNumbers(int createNumber) {
            var codeNumbers = new List<string>();
            for (int i = 1; i <= createNumber; i++)
            {
                var rndNumber = new Random(Guid.NewGuid().GetHashCode()).Next(100000, 999999).ToString();
                codeNumbers.Add(rndNumber);
            }

            return codeNumbers;
        }

        public async Task<OperationResult> EmptyRedeemCodes(Guid packageId)
        {
            using (var db = new Db())
            {
                await db.RedeemCode.Where(s => s.Package.Id == packageId).DeleteAsync();
                var package = await db.GoodsPackage.SingleAsync(s => s.Id == packageId);
                package.TotalRedeemCode = 0;
                await db.SaveChangesAsync();

                return new OperationResult() { success = true };
            }
        }

        public async Task<RedeemCode> GetRedeemCodeBySNAsync(string redeemCodeSN)
        {
            using (var db = new Db())
            {
                return await db.RedeemCode.Include("Package").SingleOrDefaultAsync(s=>s.CodeNumber == redeemCodeSN);
            }
        }

        public async Task<List<RedeemCode>> GetRedeemCodesByOrderId(Guid orderId)
        {
            using (var db = new Db())
            {
                return await db.RedeemCode.Where(s => s.ExchangeOrderId.HasValue && s.ExchangeOrderId.Value == orderId).ToListAsync();
            }
        }

        public async Task<OperationResult> RemoveLinkPackageGoods(Guid packageId, Guid[] guid)
        {
            using (var db = new Db())
            {
                var package = await db.GoodsPackage.Include("Goods").SingleAsync(s => s.Id == packageId);
                foreach (var item in guid)
                {
                    package.Goods.Remove(db.Goods.Single(s => s.Id == item));
                }

                await db.SaveChangesAsync();

                return new OperationResult() { success = true };
            }
        }

        public async Task<OperationResult> SavePackageDescription(Guid id, string description)
        {
            using (var db = new Db())
            {
                var package = await db.GoodsPackage.FindAsync(id);
                package.Description = description;

                await db.SaveChangesAsync();

                return new OperationResult() { success = true };
            }
        }

        public GridResult<RedeemCodeDto> GetRedeemCodes(int page, int rows, string sort = "r.CreationTime", string order = "asc", Guid? packageId = default(Guid?), string filterRules = "")
        {
            using (var db = new Db())
            {
                var q = from r in db.RedeemCode.Include("Package").AsQueryable()
                        join p in db.GoodsPackage.AsQueryable() on r.Package.Id equals p.Id
                        join u in db.User.AsQueryable() on r.ExchangeUserId equals u.Id into us
                        from usi in us.DefaultIfEmpty()
                        join o in db.Order.AsQueryable() on r.ExchangeOrderId equals o.Id into os
                        from osi in os.DefaultIfEmpty()
                        select new { r, usi, p, osi };

                if (packageId.HasValue)
                    q = q.Where(s => s.p.Id == packageId.Value);

                var total = q.LongCount();
                var items = q.Paged(page, rows, sort, order).ToList();

                return new GridResult<RedeemCodeDto>
                {
                    total = total,
                    rows = items.Select(s => new RedeemCodeDto {
                        Id = s.r.Id,
                        CodeNumber = s.r.CodeNumber,
                        CreationTime = s.r.CreationTime,
                        CreatorUserId = s.r.CreatorUserId,
                        OrderSN = s.osi == null ? "" : s.osi.OrderSN,
                        ExchangeTime = s.r.ExchangeTime,
                        UserName = s.usi == null ? "" : s.usi.UserName,
                        IsExchange = s.r.IsExchange,
                        PackageName = s.p.PackageName,
                        TotalRedeemCode = s.p.TotalRedeemCode,
                        LastModificationTime= s.r.LastModificationTime,
                        LastModifierUserId= s.r.LastModifierUserId
                    }).ToList()
                };
            }
        }
    }
}
